/*
 * ========THE SOLMIX PROJECT=====================================
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.gnu.org/licenses/ 
 * or see the FSF site: http://www.fsf.org. 
 */

package org.solmix.fmk.util;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.solmix.api.exception.SLXException;
import org.solmix.api.serialize.XMLParser;
import org.solmix.api.serialize.XMLParserFactory;
import org.solmix.api.types.Texception;
import org.solmix.api.types.Tmodule;
import org.solmix.commons.util.DataUtil;
import org.solmix.fmk.serialize.XMLParserFactoryImpl;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;

/**
 * 
 * @author solomon
 * @version $Id$ 2011-4-18
 */
@SuppressWarnings("unchecked")
public class XMLUtil
{

    public static Set<String> ignoreNamespaceAttributes = new HashSet<String>();
    static {
        ignoreNamespaceAttributes.add("http://www.w3.org/2000/10/XMLSchema-instance");
        ignoreNamespaceAttributes.add("http://www.solmix.org/xmlns/requestdata/v");
    }

    /**
     * @param element
     * @return
     */
    public static Map attributesToMap(Element element) {
        return addAttributesToMap(element, null);
    }

    public static boolean isIgnoreNS(String nameSpace) {
        for (String ns : ignoreNamespaceAttributes) {
            if (nameSpace.startsWith(ns))
                return true;
        }
        return false;
    }

    /**
     * @param element the giving Element
     * @param valueMap the return Map
     */
    public static Map<String, String> addAttributesToMap(Element element, Map<String, String> map) {
        if (map == null)
            map = new HashMap<String, String>();
        if (element.hasAttributes()) {
            NamedNodeMap attrs = element.getAttributes();
            for (int i = 0; i < attrs.getLength(); i++) {
                Node attr = attrs.item(i);
                String namespace = attr.getNamespaceURI();
                if (namespace != null && isIgnoreNS(namespace))
                    continue;
                String attrName = attr.getLocalName();
                if (attrName == null)
                    attrName = attr.getNodeName();
                if (attrName.equals("_BLANK_"))
                    attrName = "";
                if (!map.containsKey(attrName))
                    map.put(attrName, attr.getNodeValue());
            }
        }
        return map;
    }

    public static Map getElementChildrenMap(Element element) {
        Map elementChildren = new HashMap();
        NodeList children = element.getChildNodes();
        for (int i = 0; i < children.getLength(); i++) {
            Node child = children.item(i);
            if (child instanceof Element) {
                Element childElement = (Element) child;
                DataUtil.putMultiple(elementChildren, childElement.getTagName(), childElement);
            }
        }

        return elementChildren;
    }

    public static List<Element> getElementChildren(Element element) {
        return getElementChildren(element, (Map) null);
    }

    public static List<Element> getElementChildren(Element element, String tagName) {
        return getElementChildren(element, DataUtil.buildMap(tagName, new Object()));
    }

    public static List<Element> getElementChildren(Element element, Map tags) {
        List<Element> elementChildren = new ArrayList<Element>();
        NodeList children = element.getChildNodes();
        for (int i = 0; i < children.getLength(); i++) {
            Node child = children.item(i);
            if (!(child instanceof Element))
                continue;
            Element childElement = (Element) child;
            if (tags == null || tags.containsKey(childElement.getTagName()))
                elementChildren.add(childElement);
        }

        return elementChildren;
    }

    public static String toSimpleValue(Element element) {
        if (!element.hasChildNodes())
            return getAttribute(element, "value");
        Writer out = new StringWriter();
        NodeList children = element.getChildNodes();
        for (int i = 0; i < children.getLength(); i++)
            try {
                Node child = children.item(i);
                if (child instanceof Text) {
                    out.write(((Text) child).getData());
                    continue;
                }
            } catch (IOException impossible) {
            }

        return out.toString();
    }

    /**
     * @param element
     * @param string
     * @return
     */
    public static String getAttribute(Element element, String eleName) {
        return element.getAttribute(eleName);
    }

    public static void toFile(String location, String fileName, Object jaxbObject) throws SLXException {
        XMLParserFactory factory = new XMLParserFactoryImpl();
        XMLParser parser = factory.get();
        String absolutePath = null;
        if (location != null) {
            absolutePath = location.endsWith("/") ? location : location + "/";
            File dir = new File(absolutePath);
            if (!dir.exists() && !dir.isDirectory())
                dir.mkdirs();
            absolutePath = DataUtil.isNullOrEmpty(fileName) ? absolutePath : absolutePath + fileName;
        } else {
            absolutePath = fileName;
        }
        Writer out = null;
        FileOutputStream outStream = null;
        try {
            File f = new File(absolutePath);
            try {
                if (!f.exists()) {
                    f.createNewFile();
                }
                outStream = new FileOutputStream(f);
                out = new BufferedWriter(new OutputStreamWriter(outStream));
            } catch (Exception e) {
                throw new SLXException(Tmodule.XML, Texception.IO_EXCEPTION, e);
            }
            parser.marshalDS(out, jaxbObject);
        } finally {
            try {
                out.close();
                outStream.close();
            } catch (IOException e) {
            }
        }
    }

    public static void toFile(String fileName, Object jaxbObject) throws SLXException {
        toFile(null, fileName, jaxbObject);
    }
}
